package cn.edu.jxau.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Objects;

import cn.edu.jxau.util.LinkedQueue;

/**
 * CSV索引与反向索引
 * @author 付大石
 *
 */
public class CSVIndex {

    public static void main(String[] args) throws IOException {

        CSVIndex index = new CSVIndex();
        index.append(new File("C:\\Users\\PC-Clive\\Desktop\\data.csv"));
        for (String str : index.tsGet("吴京")) {
            System.out.print(str + " ");
        }
        System.out.println();
        for (String str : index.tsGet("甄子丹")) {
            System.out.print(str + " ");
        }
        System.out.println();
        for (String str : index.stGet("战狼")) {
            System.out.print(str + " ");
        }
        System.out.println();
        for (String str : index.tsGet("王宝强")) {
            System.out.print(str + " ");
        }
    }

    private SeparateChainingHashST<String, LinkedQueue<String>> st; // 正向索引
    private SeparateChainingHashST<String, LinkedQueue<String>> ts; // 反向索引

    public CSVIndex() {
        st = new SeparateChainingHashST<String, LinkedQueue<String>>();
        ts = new SeparateChainingHashST<String, LinkedQueue<String>>();
    }

    public CSVIndex(File csvFile) throws IOException {
        this(csvFile, ",");
    }

    public CSVIndex(File csvFile, String regex) throws IOException {
        this(csvFile, 0, regex);
    }

    public CSVIndex(File csvFile, int keyIndex, String regex) throws IOException {

        // 参数校验 //
        check(csvFile, keyIndex, regex);

        st = new SeparateChainingHashST<String, LinkedQueue<String>>();
        ts = new SeparateChainingHashST<String, LinkedQueue<String>>();
        read(csvFile, keyIndex, regex);

    }

    private void check(File csvFile, int keyIndex, String regex) throws IOException {

        Objects.requireNonNull(csvFile, "参数csvFile不能为null");
        if (!csvFile.getName().endsWith(".csv")) {
            throw new IOException("文件类型错误，仅支持.csv文件，文件路径：" + csvFile.getCanonicalPath());
        }
        if (!csvFile.exists()) {
            throw new IOException("文件不存在，文件路径：" + csvFile.getCanonicalPath());
        }
        if (!csvFile.isFile()) {
            throw new IOException("不可指定一个文件夹，文件路径：" + csvFile.getCanonicalPath());
        }
        if (!csvFile.canRead()) {
            throw new IOException("文件不可读，文件路径：" + csvFile.getCanonicalPath());
        }
        Objects.requireNonNull(regex, "参数regex不能为null");
        if (keyIndex < 0) {
            throw new IllegalArgumentException("参数keyIndex不能为负数");
        }
    }

    private void read(File csvFile, int keyIndex, String regex) throws IOException {

        try (FileReader fileReader = new FileReader(csvFile);
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(new FileInputStream(csvFile), "gbk"))) {
            String line = null;
            String[] data = null;
            while ((line = reader.readLine()) != null) {
                data = line.split(regex);
                String key = data[keyIndex];
                if (st.get(key) == null) {
                    st.put(key, new LinkedQueue<String>());
                }
                for (int i = 0; i < data.length; i++) {
                    if (i == keyIndex) {
                        continue;
                    }
                    st.get(key).enqueue(data[i]);
                    if (ts.get(data[i]) == null) {
                        ts.put(data[i], new LinkedQueue<String>());
                    }
                    ts.get(data[i]).enqueue(key);
                }
            }
        } catch (IOException e) {
            throw new IOException("文件读取失败，文件路径：" + csvFile.getCanonicalPath(), e);
        }
    }

    public Iterable<String> stGet(String key) {
        return st.get(key);
    }

    public Iterable<String> tsGet(String key) {
        return ts.get(key);
    }

    public void append(File csvFile) throws IOException {
        append(csvFile, ",");
    }

    public void append(File csvFile, String regex) throws IOException {
        append(csvFile, 0, regex);
    }

    public void append(File csvFile, int keyIndex, String regex) throws IOException {
        check(csvFile, keyIndex, regex);
        read(csvFile, keyIndex, regex);
    }
}
